package com.lry.rpc.v1;

import com.lry.common.ProtocolConstants;
import com.lry.compressor.Compressor;
import com.lry.compressor.CompressorFactory;
import com.lry.protocol.RpcMessage;
import com.lry.rpc.netty.MsgType;
import com.lry.serialize.HeadMapSerializer;
import com.lry.serialize.Serializer;
import com.lry.serialize.SerializerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

//出站，将实体变成二进制字节流
@Slf4j
public class ProtocolV1Encoder extends MessageToByteEncoder {

    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
        try {
            if(msg instanceof RpcMessage){
                RpcMessage rpcMessage = (RpcMessage) msg;

                int fullLength = ProtocolConstants.V1_HEAD_LENGTH;
                int headLength = ProtocolConstants.V1_HEAD_LENGTH;

                byte messageType = rpcMessage.getMessageType();
                out.writeBytes(ProtocolConstants.MAGIC_CODE_BYTES);
                out.writeByte(ProtocolConstants.VERSION);
                //将写索引推后6字节，因为fullLen和headerLen要占用当前6字节
                out.writerIndex(out.writerIndex() + 6);

                out.writeByte(messageType);
                out.writeByte(rpcMessage.getSerializer());
                out.writeByte(rpcMessage.getCompressor());
                out.writeInt(rpcMessage.getRequestId());

                //header
                Map<String, String> headMap = rpcMessage.getHeadMap();
                if (headMap != null && !headMap.isEmpty()) {
                    int headMapBytesLength = HeadMapSerializer.getInstance().encode(headMap, out);
                    headLength += headMapBytesLength;
                    fullLength += headMapBytesLength;
                }

                //body
                byte[] bodyBytes = null;
                if (messageType != MsgType.HEARTBEAT_REQUEST.getCode()
                        && messageType != MsgType.HEARTBEAT_RESPONSE.getCode()) {
                    // heartbeat has no body
                    Serializer serializer = SerializerFactory.getSerializer(rpcMessage.getSerializer());
                    bodyBytes = serializer.serialize(rpcMessage.getBody());
                    Compressor compressor = CompressorFactory.getCompressor(rpcMessage.getCompressor());
                    bodyBytes = compressor.compress(bodyBytes);
                    fullLength += bodyBytes.length;
                 }

                if (bodyBytes != null) {
                    out.writeBytes(bodyBytes);
                }
                //备份写索引
                int writeIndex = out.writerIndex();

                //写fullLen和headerLen
                // skip magic code(2B) + version(1B)
                //+3是因需要跳过魔数和版本，定位到正确的写的位置
                out.writerIndex(writeIndex - fullLength + 3);
                out.writeInt(fullLength);
                out.writeShort(headLength);

                //重置写索引
                out.writerIndex(writeIndex);
            }else {
                throw new UnsupportedOperationException("Not support this class:" + msg.getClass());
            }
        } catch (Throwable e) {
            log.error("Encode request error!", e);
        }
    }
}
